#include "Log.hpp"
#include <iostream>
#include <cstring>
#include <cassert>
#include <cerrno>

// 定义全局日志实例
Log lg;

Log::Log(){
    printMethod = Screen;
    minLevel = Info;
    path = "./log/";
    // 创建日志目录
    mkdir(path.c_str(), 0755);
}

Log::~Log(){
    // 清理资源
}

// 设置日志输出方式
void Log::Enable(int method){
    std::lock_guard<std::mutex> lock(mutex_);
    printMethod = method;
}

// 设置日志级别阈值
void Log::SetLevel(int level){
    std::lock_guard<std::mutex> lock(mutex_);
    minLevel = level;
}

// 设置日志文件路径
void Log::SetPath(const std::string& logPath){
    std::lock_guard<std::mutex> lock(mutex_);
    path = logPath;
    if(path.back() != '/') {
        path += "/";
    }
    // 确保目录存在
    mkdir(path.c_str(), 0755);
}

// 将日志级别转换为字符串
std::string Log::levelToString(int level){
    switch(level){
        case Info:
            return "Info";
        case Debug:
            return "Debug";
        case Warning:
            return "Warning";
        case Error:
            return "Error";
        case Fatal:
            return "Fatal";
        default:
            return "None";
    }
}

// 获取当前时间戳字符串
std::string Log::getCurrentTime(){
    struct timeval tv;
    gettimeofday(&tv, NULL);
    
    struct tm* tm_info = localtime(&tv.tv_sec);
    char buffer[64];
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
    
    char result[80];
    snprintf(result, sizeof(result), "%s.%03ld", buffer, tv.tv_usec/1000);
    return std::string(result);
}

// 格式化并输出日志
void Log::printLog(int level, const std::string &logtxt){
    // 检查日志级别
    if(level < minLevel) {
        return;
    }
    
    std::lock_guard<std::mutex> lock(mutex_);
    switch (printMethod) {
        case Screen:
            std::cout << logtxt << std::endl;
            break;
        case Onefile:
            printOneFile(LogFile, logtxt);
            break;
        case Classfile:
            printClassFile(level, logtxt);
            break;
        default:
            std::cout << logtxt << std::endl;
            break;
    }
}

// 写入单个日志文件
void Log::printOneFile(const std::string &logname, const std::string &logtxt){
    std::string _logname = path + logname;
    int fd = open(_logname.c_str(), O_WRONLY|O_CREAT|O_APPEND, 0666);
    if(fd < 0) return;
    write(fd, logtxt.c_str(), logtxt.size());
    write(fd, "\n", 1);
    close(fd);
}

// 按日志级别分类写入不同文件
void Log::printClassFile(int level, const std::string &logtxt){
    std::string filename = LogFile;
    filename += ".";
    filename += levelToString(level);
    printOneFile(filename, logtxt);
}

// 重载函数调用操作符，支持格式化日志输出
void Log::operator()(int level, const char* format, ...){
    // 检查日志级别
    if(level < minLevel) {
        return;
    }
    
    // 获取当前时间
    std::string currentTime = getCurrentTime();
    
    // 格式化日志级别和时间
    char leftbuffer[SIZE];
    snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%s]", 
             levelToString(level).c_str(), currentTime.c_str());
    
    // 处理可变参数
    va_list args;
    va_start(args, format);
    char rightbuffer[SIZE];
    vsnprintf(rightbuffer, sizeof(rightbuffer), format, args);
    va_end(args);

    // 组合完整日志信息
    char logtxt[SIZE*2];
    snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);
    printLog(level, std::string(logtxt));
}

// 提供不同级别的便捷方法
void Log::info(const char* format, ...){
    va_list args;
    va_start(args, format);
    log(Info, format, args);
    va_end(args);
}

void Log::debug(const char* format, ...){
    va_list args;
    va_start(args, format);
    log(Debug, format, args);
    va_end(args);
}

void Log::warning(const char* format, ...){
    va_list args;
    va_start(args, format);
    log(Warning, format, args);
    va_end(args);
}

void Log::error(const char* format, ...){
    va_list args;
    va_start(args, format);
    log(Error, format, args);
    va_end(args);
}

void Log::fatal(const char* format, ...){
    va_list args;
    va_start(args, format);
    log(Fatal, format, args);
    va_end(args);
}

// 内部日志记录方法
void Log::log(int level, const char* format, va_list args){
    if(level < minLevel) {
        return;
    }
    
    std::string currentTime = getCurrentTime();
    char leftbuffer[SIZE];
    snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%s]", 
             levelToString(level).c_str(), currentTime.c_str());
    
    char rightbuffer[SIZE];
    vsnprintf(rightbuffer, sizeof(rightbuffer), format, args);
    
    char logtxt[SIZE*2];
    snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);
    printLog(level, std::string(logtxt));
}